﻿using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Media.Media3D;

namespace ZOIL.Library.Behaviors
{
    public static class ZBehavior
    {
        /// <summary>
        /// Helper function to handle changes of attached properties: 
        /// If new value is not null or true, specified handler is registered for specified event at specified UI element.
        /// If new value is null or false, specified handler is removed for specified event at specified UI element.
        /// </summary>
        /// <param name="oldValue"></param>
        /// <param name="newValue"></param>
        /// <param name="element"></param>
        /// <param name="targetEvent"></param>
        /// <param name="handler"></param>
        public static void HandleChange(object oldValue, object newValue, UIElement element, RoutedEvent targetEvent, Delegate handler)
        {
            if (element == null) return;

            // If we're putting in a new command and there wasn't one already hook the event
            if ((newValue != null) && (oldValue == null || !(bool)oldValue))
            {
                element.AddHandler(targetEvent, handler);
            }
                // If we're clearing the command and it wasn't already null unhook the event
            else if ((newValue == null || !(bool)newValue) && (oldValue != null))
            {
                element.RemoveHandler(targetEvent, handler);
            }
        }

        public static void ExecuteCommand(UIElement sender, DependencyProperty commandProperty)
        {
            var command = (RoutedCommand)sender.GetValue(commandProperty);
            var parameter = sender.GetValue(ParameterProperty);
            command.Execute(parameter, sender);
        }

        public static void ExecuteCommand(UIElement sender, DependencyProperty commandProperty, Object parameter)
        {
            var command = (RoutedCommand)sender.GetValue(commandProperty);
            command.Execute(parameter, sender);
        }

        #region tree helper

        public static UIElement FindCanvasChild(DependencyObject depObj)
        {
            if (depObj == null)
                throw new ArgumentNullException("depObj");

            var parent = VisualTreeHelper.GetParent(depObj);
            
            var elem = depObj as UIElement;

            if (parent is Canvas && elem != null && (parent as Canvas).Children.Contains(elem))
                return elem;

            if (depObj is Visual || depObj is Visual3D)
                return FindCanvasChild(VisualTreeHelper.GetParent(depObj));

            return FindCanvasChild(LogicalTreeHelper.GetParent(depObj));
        }

        #endregion

        #region Parameter
        
        public static readonly DependencyProperty ParameterProperty = DependencyProperty.RegisterAttached(
                "Parameter",
                typeof(object),
                typeof(ZBehavior),
                new FrameworkPropertyMetadata((object)null, null));

        public static object GetParameter(DependencyObject d)
        {
            return d.GetValue(ParameterProperty);
        }

        public static void SetParameter(DependencyObject d, object value)
        {
            d.SetValue(ParameterProperty, value);
        }

        #endregion
    }
}
